package ace.cmp.core.model;

import ace.cmp.core.enums.BaseEnum;
import ace.cmp.core.enums.SystemCodeEnum;
import ace.cmp.core.exception.BusinessException;
import java.util.Map;
import java.util.Objects;
import java.util.function.Supplier;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.SuperBuilder;

/**
 * @author caspar
 * @contact
 * @date 2017/1/19 通用出参数对象
 */
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class R<T> {

  public static final Integer OK = SystemCodeEnum.SUCCESS.getCode();

  /**
   * 返回结果
   */
  private T data;

  /**
   * 返回代码
   * {@link SystemCodeEnum}
   */
  private Integer code;

  /**
   * 返回消息
   */
  private String message;

  /**
   * 扩展参数
   */
  private Map<String, Object> extras;

  /**
   * 成功，则返回数据,失败则丢出业务异常信息
   *
   * @return
   */
  public T check() {
    if (this.success() == false) {
      throw new BusinessException(this.getCode(), this.getMessage());
    }
    return this.getData();
  }

  /**
   * 成功，则返回数据,失败则丢出业务异常信息
   *
   * @return
   */
  public T check(String message) {
    if (this.success() == false) {
      throw new BusinessException(this.getCode(), message);
    }
    return this.getData();
  }

  public T check(Integer code, String message) {
    if (this.success() == false) {
      throw new BusinessException(code, message);
    }
    return this.getData();
  }

  public T checkAndDataIsNonNull(Supplier<RuntimeException> exceptionSupplier) {
    T data = this.check();

    if (Objects.isNull(data)) {
      throw exceptionSupplier.get();
    }
    return data;
  }

  public boolean success() {
    return SystemCodeEnum.SUCCESS.getCode().equals(this.getCode());
  }

  /**
   * 成功则返回调用结果，否则  throw new BusinessException(R.getCode(), R.getMessage());
   *
   * @param supplier
   * @param <T>
   * @return
   */
  public static <T> T getAndCheck(Supplier<R<T>> supplier) {
    R<T> r = supplier.get();
    if (SystemCodeEnum.SUCCESS.getCode().equals(r.getCode())) {
      return r.getData();
    }
    throw new BusinessException(r.getCode(), r.getMessage());
  }

  public static <T> R<T> ok() {
    return R.<T>builder()
        .code(SystemCodeEnum.SUCCESS.getCode())
        .message(SystemCodeEnum.SUCCESS.getDesc())
        .data(null)
        .build();
  }

  public static <T> R<T> ok(T data) {
    return R.<T>builder()
        .code(SystemCodeEnum.SUCCESS.getCode())
        .message(SystemCodeEnum.SUCCESS.getDesc())
        .data(data)
        .build();
  }

  public static <T> R<T> fail() {
    return R.<T>builder()
        .code(SystemCodeEnum.BUSINESS_EXCEPTION.getCode())
        .message(SystemCodeEnum.BUSINESS_EXCEPTION.getDesc())
        .data(null)
        .build();
  }

  public static <T> R<T> fail(T data) {
    return R.<T>builder()
        .code(SystemCodeEnum.BUSINESS_EXCEPTION.getCode())
        .message(SystemCodeEnum.BUSINESS_EXCEPTION.getDesc())
        .data(data)
        .build();
  }

  public static <T> R<T> fail(String message) {
    return R.<T>builder()
        .code(SystemCodeEnum.BUSINESS_EXCEPTION.getCode())
        .message(message)
        .build();
  }

  public static <T> R<T> fail(Integer code, String message) {
    return R.<T>builder().code(code).message(message).data(null).build();
  }

  public static <T> R<T> fail(Integer code, String message, T data) {
    return R.<T>builder().code(code).message(message).data(data).build();
  }

  public static <T> R<T> fail(T data, BaseEnum<Integer> errorEnum) {
    return R.<T>builder().code(errorEnum.getCode()).message(errorEnum.getDesc()).data(data).build();
  }

  public static <T> R<T> create(BaseEnum<Integer> errorEnum) {
    return R.<T>builder().code(errorEnum.getCode()).message(errorEnum.getDesc()).data(null).build();
  }

  /**
   * 复制,不包含data字段.
   */
  public static <T> R<T> of(R result, T data) {
    return R.<T>builder()
        .data(data)
        .code(result.getCode())
        .message(result.getMessage())
        .extras(result.getExtras())
        .build();
  }
}
